﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using Moq;

namespace MvcWiki.Test.Repository.UnitOfWork
{
    public class DeletedFacts
    {
        [Fact]
        public void Can_Call()
        {
            var unitOfWorkPersistence = new Mock<MvcWiki.Repository.IUnitOfWorkPersistence>();

            var unitOfWork = new MvcWiki.Repository.UnitOfWork();

            var entity = new MvcWiki.Model.WikiPage();

            unitOfWork.Deleted(entity, unitOfWorkPersistence.Object);
        }

        [Fact]
        public void Calls_IUnitOfWorkPersistence_DeletetEntity_On_Commit()
        {
            var entity = new MvcWiki.Model.WikiPage();

            var unitOfWorkPersistence = new Mock<MvcWiki.Repository.IUnitOfWorkPersistence>(MockBehavior.Strict);
            unitOfWorkPersistence.Setup(x => x.DeleteEntity(entity));

            var unitOfWork = new MvcWiki.Repository.UnitOfWork();

            unitOfWork.Selected(entity, unitOfWorkPersistence.Object);
            unitOfWork.Deleted(entity, unitOfWorkPersistence.Object);

            unitOfWork.Commit();

            unitOfWorkPersistence.VerifyAll();
        }

        [Fact]
        public void Does_Not_Call_IUnitOfWorkPersistence_DeletetEntity_On_Commit_If_Entity_Was_Not_Selected()
        {
            var entity = new MvcWiki.Model.WikiPage();

            var unitOfWorkPersistence = new Mock<MvcWiki.Repository.IUnitOfWorkPersistence>(MockBehavior.Strict);

            var unitOfWork = new MvcWiki.Repository.UnitOfWork();

            unitOfWork.Deleted(entity, unitOfWorkPersistence.Object);

            unitOfWork.Commit();

            unitOfWorkPersistence.VerifyAll();
        }

        [Fact]
        public void Calls_IUnitOfWorkPersistence_Delete_For_WikiPages_Then_For_WikiNamespaces()
        {
            var wikiPage = new MvcWiki.Model.WikiPage();
            var wikiNamespace = new MvcWiki.Model.WikiNamespace();

            bool wikiNamespaceDeletedLast = false;
            bool wikiPageDeletedLast = false;

            var unitOfWorkPersistenceForWikiPage = new Mock<MvcWiki.Repository.IUnitOfWorkPersistence>();
            unitOfWorkPersistenceForWikiPage.Setup(x => x.DeleteEntity(wikiPage))
                .Callback(() => { wikiNamespaceDeletedLast = false; wikiPageDeletedLast = true; });

            var unitOfWorkPersistenceForWikiNamespace = new Mock<MvcWiki.Repository.IUnitOfWorkPersistence>();
            unitOfWorkPersistenceForWikiNamespace.Setup(x => x.DeleteEntity(wikiNamespace))
                .Callback(() => { wikiNamespaceDeletedLast = true; wikiPageDeletedLast = false; });

            var unitOfWork = new MvcWiki.Repository.UnitOfWork();

            unitOfWork.Selected(wikiPage, unitOfWorkPersistenceForWikiPage.Object);
            unitOfWork.Selected(wikiNamespace, unitOfWorkPersistenceForWikiNamespace.Object);

            unitOfWork.Deleted(wikiPage, unitOfWorkPersistenceForWikiPage.Object);
            unitOfWork.Deleted(wikiNamespace, unitOfWorkPersistenceForWikiNamespace.Object);

            unitOfWork.Commit();

            Assert.True(wikiNamespaceDeletedLast);
            Assert.False(wikiPageDeletedLast);
        }

        [Fact]
        public void Does_Not_Call_IUnitOfWorkPersistence_DeleteEntity_On_Second_Commit()
        {
            var entity = new MvcWiki.Model.WikiPage();

            var deleteEntityCalls = 0;

            var unitOfWorkPersistence = new Mock<MvcWiki.Repository.IUnitOfWorkPersistence>();
            unitOfWorkPersistence.Setup(x => x.DeleteEntity(entity)).Callback(() => deleteEntityCalls++);

            var unitOfWork = new MvcWiki.Repository.UnitOfWork();

            unitOfWork.Selected(entity, unitOfWorkPersistence.Object);
            unitOfWork.Deleted(entity, unitOfWorkPersistence.Object);

            unitOfWork.Commit();
            unitOfWork.Commit();

            Assert.Equal<int>(1, deleteEntityCalls);
        }
    }
}
